package freedom.utils.enumplus;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Objects;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.usertype.DynamicParameterizedType;
import org.hibernate.usertype.UserType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**  
* @author charlie tingfangcao@163.com  
* @date 2019年12月26日 上午11:08:27  
*    
*/
public class ValueEnumType implements UserType, DynamicParameterizedType {
    
    static Logger log = LoggerFactory.getLogger(ValueEnumType.class);

	private Class<?> enumClass;
	private static final int[] SQL_TYPES = new int[] { Types.VARCHAR };

	@Override
	public void setParameterValues(Properties parameters) {
		final ParameterType reader = (ParameterType) parameters.get(PARAMETER_TYPE);
		if (reader != null) {
			Class<?> clazz = reader.getReturnedClass();
			enumClass = clazz.asSubclass(Enum.class);// 自动寻找枚举
		}
	}

	@Override
	public int[] sqlTypes() {
		return SQL_TYPES;
	}

	@Override
	public Class<?> returnedClass() {
		return enumClass;
	}

	// 是否相等，不相等会触发JPA update操作
	@Override
	public boolean equals(Object x, Object y) throws HibernateException {
		if (x == null && y == null) {
			return true;
		}
		if ((x == null && y != null) || (x != null && y == null)) {
			return false;
		}
		return x.equals(y);
	}

	@Override
	public int hashCode(Object x) throws HibernateException {
		return x == null ? 0 : x.hashCode();
	}

	// 返回枚举
	@Override
	public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
			throws HibernateException, SQLException {
		String value = rs.getString(names[0]);
//		log.debug("get value:{}", value);
		if (value == null) {
			return null;
		}
		for (Object object : enumClass.getEnumConstants()) {
			if (Objects.equals(value, String.valueOf(((EnumPlus) object).getValue()))) {
				return object;
			}
		}
		throw new RuntimeException(String.format("unsupported value [%s] for enum class [%s]", value, enumClass.getName()));
	}

	// 保存枚举值
	@Override
	public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
			throws HibernateException, SQLException {
		log.debug("set value:{}", value);
		if (value == null) {
			st.setNull(index, SQL_TYPES[0]);
		} else {
			st.setString(index, String.valueOf(((EnumPlus) value).getValue()));
		}
	}

	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	@Override
	public boolean isMutable() {
		return false;
	}

	@Override
	public Serializable disassemble(Object value) throws HibernateException {
		return (Serializable) value;
	}

	@Override
	public Object assemble(Serializable cached, Object owner) throws HibernateException {
		return cached;
	}

	@Override
	public Object replace(Object original, Object target, Object owner) throws HibernateException {
		return original;
	}
}
